iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0
Modern Web

LV的全端開發體驗系列 第 26

Day26 讓數字視覺化 - 引入Apache ECharts

  • 分享至 

  • xImage
  •  

看著鐵人賽快到尾聲了,但我只做完骨架功能而已,有點慚愧;幸好這周有雙十連假,可以稍微趕一下進度。

在我的計劃中,之後的功能如果會有數字分析的地方,都希望能儘量以圖像化的方式呈現,因此需要有一個機制來方便圖像的產生,在這之前我大多都是使用 Chart.js,但是有一些呈現方式在Chart.js中很麻煩,Chart.js還開了一個 youtube 頻道來教學,想證明自己什麼圖都畫得出來;

後來有朋友介紹 Apache ECharts 這個開源專案,有些功能似乎已經做好了,有很多已經做好的範例,甚至還提供線上工具讓你先模擬好各項參數的效果後就可以直接使用了,想說就來試試看吧;

按照官網指示來安裝:

npm install echarts --save

網路上找了一些教學,大多都是用 js 先封裝成模組再匯入到 Vue 來使用的,但我想直接做成一個組件來使用,所以先把官網範例抓過來測試一下:
resources\js\ChartComponents\PieChart.vue

<script setup>
import * as echarts from 'echarts/core';
import { PieChart } from 'echarts/charts';
import { TitleComponent, TooltipComponent, LegendComponent} from 'echarts/components';
import { LabelLayout } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';
import { ref ,onMounted} from 'vue';

echarts.use([PieChart, TitleComponent, TooltipComponent, LegendComponent,
             CanvasRenderer, LabelLayout]);

const canvas = ref(null);

//以下無情複製官網範例
const option = {
  title: {
    text: 'Referer of a Website',
    subtext: 'Fake Data',
    left: 'center'
  },
  tooltip: {
    trigger: 'item'
  },
  legend: {
    orient: 'vertical',
    left: 'left'
  },
  series: [
    {
      name: 'Access From',
      type: 'pie',
      radius: '50%',
      data: [
        { value: 1048, name: 'Search Engine' },
        { value: 735, name: 'Direct' },
        { value: 580, name: 'Email' },
        { value: 484, name: 'Union Ads' },
        { value: 300, name: 'Video Ads' }
      ],
      emphasis: {
        itemStyle: {
          shadowBlur: 10,
          shadowOffsetX: 0,
          shadowColor: 'rgba(0, 0, 0, 0.5)'
        }
      }
    }
  ]
};

onMounted(()=>{
//在onMounted中取得DOM
const pie=echarts.init(canvas.value)
//取得DOM後加入設定參數開始繪製
pie.setOption(option)
})
</script>
<template>
    <div  ref="canvas" style="width:500px;height:500px"></div>
</template>

我開了一個資料夾來專門存放日後製作的圖表組件,然後先把範例程式碼拿來用,測試過程中有注意到,ECharts的繪圖功能必須在頁面中有 DOM 存在的前提下才能進行繪製,所以執行繪圖這件事幾乎只能放在 onMounted 事件後才能有作用

然後試試能不能在任何頁面引入這個組件來:
resources\js\Pages\Home.vue

<script setup>
    .....略
import PieChart from "@/ChartComponents/PieChart.vue";
</script>
<template>
<FrontLayout>
.....略

  <PieChart />
</FrontLayout>
</template>

接著我們把組件調整一下,做成日後可以接收 props 進來,然後繪製的彈性組件:
resources\js\ChartComponents\PieChart.vue

.....略

const props=defineProps({
  data:{
        type:Array || Object,
        default:[{value:1,name:'true'},
                 {value:1,name:'false'}]
      },
  legend:{
        type:Object,
        default:{
            orient:'vertical',
            left:'left'
        }
      },    
  options:{
    type:Object,
    default:{
      title:{
        type:Object,
        default:{
          title: '圖餅圖',
          subtitle:'資料圓餅圖',
          left:'center',
        }
      },
    }
  }
})

const canvas = ref(null);

const option = {
  title: props.options.title,
  legend: props.legend,
  tooltip: {
    trigger: 'item'
  },
  series: [
    {
      name: '',
      type: 'pie',
      radius: '50%',
      data: props.data,
      emphasis: {
        itemStyle: {
          shadowBlur: 5,
          shadowOffsetX: 0,
          shadowColor: 'rgba(0, 0, 0, 0.5)'
        }
      }
    }
  ]
};

onMounted(()=>{
  const pie=echarts.init(canvas.value)
  pie.setOption(option)
})
</script>
<template>
    <div ref="canvas" style="width:100%;height:100%"></div>
</template>

在頁面使用的方式就是把各個屬性傳入
resources\js\Pages\Home.vue

<div style="width:500px;height:500px">
 <PieChart  :legend="{orient:'vertical',left:'right'}"
            :options="{title:{text:'圓餅圖',left:'center'}}"
            :data="[{name:'北',value:10},{name:'中',value:30},{name:'南',value:50}]" />
</div>

不過在測試的過程中採了不少坑,有些設定似乎無法拉出來變成參數來傳入,但是我又查到官網的不少範例中,配置項其實是可以用程式化的方式去動態調整的,看起來是要花點時間好好研究一下。

接著我們要讓資料由後端輸出給前端使用:
app\Services\TestService.php

//在傳給Backstage的資料中加上新的資料內容
function infos()
{
    return ['count'=>$this->test->count(),
            'passed'=>$this->calcPassed()];
}

//暫時先回傳假資料
function calcPassed(){
    return [['name'=>'及格','value'=>75],
            ['name'=>'不及格','value'=>32]];
}

調整一下後台的頁面配置
resources\js\Pages\Backstage\Backstage.vue

.....略
 <div class="w-1/2 border rounded-xl flex p-4 h-1/2 bg-green-400">
          題庫:{{ infos.bank.count }}
  </div>
  <div class="w-1/2 border rounded-xl flex p-4 h-1/2 bg-sky-400">
      試卷:{{ infos.quiz.count }}
  </div>
  <div class="w-1/2 border rounded-xl flex p-4 h-1/2 bg-yellow-400">
      <div>測驗:{{ infos.test.count }}</div>
      <PieChart class="w-1/2 h-full"
                 :data="infos.test.passed" 
                 :legend="null" 
                 :options="{title:null}"/>
  </div>
  <div class="w-1/2 border rounded-xl flex p-4 h-1/2 bg-orange-400">
      群組:{{ infos.group.count }}
  </div>
.....略

最後加上大小自動調整的 resize 功能,需要去監聽 window.onresize 事件,然後呼叫 echart 物件本身的 resize() 函式,同時修改一下圓餅圖的配置項目,我想讓 label 顯示在圖塊上,同時增加數字內容:
resources\js\ChartComponents\PieChart.vue

<script setup>
.....略
const canvas = ref(null);

const option = {
  title: props.options.title,
  legend: props.legend,
  tooltip: {
    trigger: 'item'
  },
  series: [
    {
      name: '',
      type: 'pie',
      radius: '85%',  //餅圖半徑加大
      data: props.data,
      label:{ //增加對label的設定
          show:true,
          formatter:'{b}\n{c}',
          position:'inside'
      },
      emphasis: {
        itemStyle: {
          shadowBlur: 5,
          shadowOffsetX: 0,
          shadowColor: 'rgba(0, 0, 0, 0.5)'
        }
      }
    }
  ]
};

onMounted(()=>{
  const pie=echarts.init(canvas.value)
  pie.setOption(option)
    
  //建立瀏灠器的監聽事件,去觸發重畫
  window.onresize=()=>{
    pie.resize();
  }
})
</script>
<template>
    <div ref="canvas" style="width:100%;height:100%"></div>
</template>

接著就是按照需求,建立一些常用的圖表組件起來,可以隨時呼叫來使用,也有不少高手提供了已經封裝好給 vue 使用的 ECharts 套件,有興趣的可以去找來玩玩,我今天的主要目的是了解ECharts和Chart.js有什麼差異,整體來說,配置的部份都很麻煩,但是ECharts官網提供的圖表範例真的是超豐富的,API的說明也很清楚,這點對開發者來說超級重要的。


上一篇
Day25 使用者的後台觀看權限 - Route & Middleware
下一篇
Day27 計分模式 - 前置規劃做的好,改東改西沒煩惱
系列文
LV的全端開發體驗30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言